#!/usr/bin/python -S
"""
cat program written using torn.
"""

__author__ = 'Andy Chu'


import os
import stat
import sys

# HACK
sys.path.append('..')

from torn import ioloop
from torn import stream  # for Stdin/Stdout
from torn import log as torn_log


class Error(Exception):
  pass


_verbose2 = False

def log(msg, *args):
  if not _verbose2:
    return
  if args:
    msg = msg % args
  print >>sys.stderr, '\t' + msg


class Cat(object):

  def __init__(self, stdin, stdout, loop):
    self.stdin = stdin
    self.stdout = stdout
    self.loop = loop
    self.all_written = True

    # Use this to test input
    stdin.on('data', self.echo)
    stdin.on('close', self.done)

  def echo(self, chunk):
    #log('CHUNK %r', chunk)

    # TODO: If not everything was written, pause stdin?  This way we don't blow
    # up the internal torn buffer.
    self.all_written = self.stdout.write(chunk)

    # NOTE: this doesn't work on pipes!
    #stdout_size = os.fstat(self.stdout.fileno())[stat.ST_SIZE]

    def resume():
      log('RESUME')
      self.stdin.resume()
      self.stdout.remove_listener('drain', resume)

    if not self.all_written:
      log('PAUSE')
      self.stdin.pause()
      # Hmm, this causes many resumes for each pause.  But a duplicate resume is
      # checked for in ReadableStream now.
      self.stdout.on('drain', resume)

  def done(self):
    log('DONE')

    # This signals that we're not going to send any more values on stdout -- I
    # guess it's closed automatically on process exit, but just do it for
    # cleanliness.
    self.stdout.close()

    if _verbose2:
      print >>sys.stderr, "stdin : %s" % dict(self.stdin.counters())
      print >>sys.stderr, "stdout: %s" % dict(self.stdout.counters())

    # Hm, this is awkward... but I guess it's necessary for command line apps.
    # We don't want to exit until everything is written.
    if not self.all_written:
      self.stdout.on('drain', self.loop.stop)
    else:
      self.loop.stop()


def main(argv):
  buffered = False
  if argv:
    if '-v' in argv:
      torn_log.install_default_logger()
    buffered = '-b' in argv
    global _verbose2
    _verbose2 = '-v2' in argv

  print >>sys.stderr, 'cat.py pid: %d' % os.getpid()

  loop = ioloop.instance()

  stdout = stream.Stdout()
  stdin = stream.Stdin()

  if buffered:
    log('BUFFERED')
    stdin.pipe(stdout)
    def done():
      log('stdout closed, done')
      loop.stop()
    stdout.on('close', done)
  else:
    Cat(stdin, stdout, loop)

  loop.start()
  return 0


if __name__ == '__main__':
  try:
    sys.exit(main(sys.argv[1:]))
  except Error, e:
    print >> sys.stderr, e.args[0]
    sys.exit(1)
